package com.hdu.aspect;

import com.hdu.util.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect //当前类为切面类
@Slf4j
public class TimeAspect {

    @Pointcut("execution(* com.hdu.service.*.*(..))")
    public void proceedingJoinPoint() {
    }

    //前置通知，此注解标注的通知方法在目标方法前被执行
    @Before("proceedingJoinPoint()")
    public void before(JoinPoint joinPoint) {
        log.info("before ...");
    }


    //环绕通知，此注解标注的通知方法在目标方法前、后都被执行
    @Around("proceedingJoinPoint()")
    public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
        //记录方法执行开始时间
        long begin = System.currentTimeMillis();

        //获取目标类名
        String name = pjp.getTarget().getClass().getName();
        log.info("目标类名：{}", name);

        //目标方法名
        String methodName = pjp.getSignature().getName();
        log.info("目标方法名：{}", methodName);

        //获取方法执行时需要的参数
        Object[] args = pjp.getArgs();
        log.info("目标方法参数：{}", Arrays.toString(args));

        //执行原始方法
        Object result = pjp.proceed();

        //记录方法执行结束时间
        long end = System.currentTimeMillis();
        

        //计算方法执行耗时
        log.info(pjp.getSignature() + "执行耗时: {}", TimeUtils.getTimeString(end - begin));

        return result;
    }

    //后置通知，此注解标注的通知方法在目标方法后被执行，无论是否有异常都会执行
    @After("proceedingJoinPoint()")
    public void after(JoinPoint joinPoint) {
        log.info("after ...");
    }

    //返回后通知（程序在正常执行的情况下，会执行的后置通知）
    @AfterReturning("proceedingJoinPoint()")
    public void afterReturning(JoinPoint joinPoint) {
        log.info("afterReturning ...");
    }

    //异常通知（程序在出现异常的情况下，执行的后置通知）
    @AfterThrowing("proceedingJoinPoint()")
    public void afterThrowing(JoinPoint joinPoint) {
        log.info("afterThrowing ...");
    }

}
